package com.xiaoshuidi.cloud.module.finance.controller.admin.finance;

import cn.hutool.core.date.DateUtil;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.PdfWriter;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.excel.core.util.ExcelUtils;
import com.xiaoshuidi.cloud.framework.operatelog.core.annotations.OperateLog;
import com.xiaoshuidi.cloud.framework.security.core.LoginUser;
import com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils;
import com.xiaoshuidi.cloud.module.contract.enums.contract.CustomerTypeEnum;
import com.xiaoshuidi.cloud.module.finance.controller.admin.finance.vo.account.*;
import com.xiaoshuidi.cloud.module.finance.convert.finance.FinanceConvert;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.finance.FinanceAccountDO;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.finance.FinanceAccountJournalExtDO;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.finance.FinanceAccountWithdrawDO;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.finance.FinanceAccountWithdrawExtDO;
import com.xiaoshuidi.cloud.module.finance.enums.finance.AccountTradeTypeEnum;
import com.xiaoshuidi.cloud.module.finance.enums.finance.FinanceAccountTypeSourceEnum;
import com.xiaoshuidi.cloud.module.finance.enums.finance.FinanceCustomerTypeEnum;
import com.xiaoshuidi.cloud.module.finance.service.finance.FinanceAccountService;
import com.xiaoshuidi.cloud.module.finance.service.finance.FinanceAccountWithdrawService;
import com.xiaoshuidi.cloud.module.finance.util.pdf.PdfUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Tag(name = "管理后台 - 账户")
@RestController
@RequestMapping("/finance/account")
public class FinanceAccountController {

    @Resource
    private FinanceAccountService financeAccountService;
    @Resource
    private FinanceAccountWithdrawService financeAccountWithdrawService;


    /**
     * 账户充值
     *
     * @return
     */
    @Operation(summary = "充值")
    @PostMapping("/recharge")
    @PreAuthorize("@ss.hasAnyPermissions('finance:account:recharge', 'finance:account:company:recharge'," +
            "'finance:account:room:recharge')")
    public CommonResult<Void> recharge(@Valid @RequestBody FinanceAccountCreateReqVO reqVO) {
        reqVO.setTradeType(AccountTradeTypeEnum.OFFLINE_RECHARGE.name());
        reqVO.setOperator(SecurityFrameworkUtils.getLoginUser().getNickname());
        financeAccountService.recharge(reqVO);
        return CommonResult.success();
    }

    /**
     * 账户扣款
     *
     * @return
     */
    @Operation(summary = "扣款")
    @PostMapping("/deduction")
    @PreAuthorize("@ss.hasAnyPermissions('finance:account:deduction', 'finance:account:company:deduction')")
    public CommonResult<Void> deduction(@Valid @RequestBody FinanceAccountCreateReqVO reqVO) {
        reqVO.setTradeType(AccountTradeTypeEnum.OFFLINE_RECHARGE.name());
        reqVO.setOperator(SecurityFrameworkUtils.getLoginUser().getNickname());
        financeAccountService.deduction(reqVO);
        return CommonResult.success();
    }

    /**
     * 分页
     *
     * @param reqVO
     * @return
     */
    @GetMapping("/page")
    @Operation(summary = "获取账户分页列表")
    @PreAuthorize("@ss.hasAnyPermissions('finance:account:query', 'finance:account:company:query')")
    public CommonResult<PageResult<FinanceAccountVO>> page(FinanceAccountPageReqVO reqVO) {
        PageResult<FinanceAccountVO> page;
        if (FinanceCustomerTypeEnum.ROOM.name().equals(reqVO.getCustType())) {
            page = financeAccountService.getRoomAccountPage(reqVO);
        } else {
            page = financeAccountService.getPage(reqVO);
        }
        return CommonResult.success(page);
    }

    /**
     * 账户信息
     *
     * @param custId
     * @param custType
     * @return
     */
    @GetMapping("/get")
    @Operation(summary = "账户信息")
    @Parameter(name = "custId", description = "租客/企业id", required = true, example = "1024")
    @Parameter(name = "custType", description = "客户类型", required = true, example = "(INDIVIDUAL(\"个人\"), COMPANY" +
            "(\"企业\"), ROOM(\"房屋\")")
    @PreAuthorize("@ss.hasAnyPermissions('finance:account:query', 'finance:account:company:query')")
    public CommonResult<FinanceAccountDO> detail(@RequestParam("custId") String custId,
                                                 @RequestParam("custType") String custType) {
        FinanceAccountDO accountDO = financeAccountService.get(custId, custType);
        return CommonResult.success(accountDO);
    }

    /**
     * @param reqVO
     * @return
     */
    @Operation(summary = "钱包流水")
    @GetMapping("/journal/page")
    @PreAuthorize("@ss.hasPermission('finance:account:journal:query')")
    public CommonResult<PageResult<FinanceAccountJournalVO>> getPage(FinanceAccountJournalPageReqVO reqVO) {
        //reqVO.setStatus(FinanceCommonStatusEnum.SUCCESS.name());
        PageResult<FinanceAccountJournalExtDO> pageResult = financeAccountService.getJournalPage(reqVO);
        return CommonResult.success(FinanceConvert.INSTANCE.convertToFinanceAccountJournalPage(pageResult));
    }

    /**
     * 个人以及房屋钱包添加流水支付方式 账单编号
     *
     * @param reqVO
     * @return
     */
    @Operation(summary = "钱包流水添加明细")
    @GetMapping("/journal/pageDetails")
    @PreAuthorize("@ss.hasPermission('finance:account:journal:query')")
    public CommonResult<PageResult<FinanceAccountJournalVO>> getJournalPageDetails(FinanceAccountJournalPageReqVO reqVO) {
        //reqVO.setStatus(FinanceCommonStatusEnum.SUCCESS.name());
        PageResult<FinanceAccountJournalExtDO> pageResult = financeAccountService.getJournalPageDetails(reqVO);
        return CommonResult.success(FinanceConvert.INSTANCE.convertToFinanceAccountJournalPage(pageResult));
    }

    /**
     * 手动退款
     *
     * @param reqVO
     * @return
     */
    @Operation(summary = "手动退款")
    @PostMapping("/refund")
    @PreAuthorize("@ss.hasAnyPermissions('finance:account:refund', 'finance:account:company:refund')")
    public CommonResult<Void> refund(@Valid @RequestBody FinanceAccountRefundReqVO reqVO) {
        financeAccountService.walletRefund(reqVO);
        return CommonResult.success();
    }

    /**
     * 账户交易明细导出
     *
     * @return
     */
    @GetMapping("/journal/export")
    @Operation(summary = "账户交易明细导出")
    @PreAuthorize("@ss.hasAnyPermissions('finance:account:journal:export', 'finance:account:company:journal:export')")
    public void export(HttpServletResponse response, FinanceAccountJournalPageReqVO reqVO) throws IOException {
        reqVO.setPageSize(100);
        //reqVO.setStatus(FinanceCommonStatusEnum.SUCCESS.name());
        PageResult<FinanceAccountJournalExtDO> pageResult = financeAccountService.getJournalPage(reqVO);
        ExcelUtils.write(response, "账户交易明细.xlsx", "账户交易明细", FinanceAccountJournalExcelVO.class, pageResult,
                FinanceConvert.INSTANCE::convertToFinanceAccountJournalExcelList, (pageNo) -> {
                    reqVO.setPageNo(pageNo);
                    return financeAccountService.getJournalPage(reqVO);
                });
    }

    /**
     * 账户提现申请列表
     *
     * @return
     */
    @GetMapping("/withdraw/page")
    @Operation(summary = "账户提现申请列表")
    public CommonResult<FinanceAccountWithdrawPageResult> withdrawPage(FinanceAccountWithdrawPageReqVO reqVO) {
        //添加过滤
//        reqVO.setIsFilter(true);
        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        PageResult<FinanceAccountWithdrawExtDO> pageResult = financeAccountWithdrawService.withdrawPage(user, reqVO);
        FinanceAccountWithdrawPageResult result = financeAccountWithdrawService.getWithdrawSummary(reqVO);
        result.setTotal(pageResult.getTotal());
        result.setList(pageResult.getList());
        return CommonResult.success(result);
    }

    /**
     * 提现导出
     */
    @GetMapping("/withdraw/export")
    public void exportSettlementExcel(FinanceAccountWithdrawPageReqVO req, HttpServletResponse response) throws IOException {
        //添加过滤
//        req.setIsFilter(true);
        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        PageResult<FinanceAccountWithdrawExtDO> pageResult = financeAccountWithdrawService.withdrawPage(user, req);
        ExcelUtils.write(response, "余额提现" + System.currentTimeMillis() + ".xlsx", "余额提现",
                FinanceAccountWithdrawExcelVO.class, pageResult,
                FinanceConvert.INSTANCE::convertToWithdrawExcelList, (pageNo) -> {
                    req.setPageNo(pageNo);
                    return financeAccountWithdrawService.withdrawPage(user, req);
                });
    }

    /**
     * 账户提现待处理头部统计
     *
     * @return
     */
    @GetMapping("/withdraw/submit/header")
    @Operation(summary = "账户提现待处理头部统计")
    public CommonResult<FinanceAccountWithdrawHeaderResult> withdrawSubmitHeader() {
        return CommonResult.success(financeAccountWithdrawService.withdrawSubmitHeader());
    }


    /**
     * 钱包申请退费详情
     *
     * @return
     */
    @GetMapping("/wallet/applyRefund/details/{id}")
    @Operation(summary = "余额提现申请详情")
    public CommonResult<FinanceAccountWithdrawDO> getWalletApplyRefundDetails(@PathVariable("id") Long id) {
        return CommonResult.success(financeAccountService.getAccountWithdrawById(id));
    }

    /**
     * 余额提现申请详情
     *
     * @return
     */
    @GetMapping("/withdraw/details/{id}")
    @Operation(summary = "余额提现申请详情")
    public CommonResult<FinanceAccountWithdrawApprovalDetails> getById(@PathVariable("id") Long id) {
        return CommonResult.success(financeAccountWithdrawService.getById(id));
    }

    /**
     * 账户提现申请列表
     *
     * @return
     */
    @PostMapping("/withdraw/confirm")
    @Operation(summary = "账户提现付款")
    public CommonResult<Void> withdrawConfirm(@Valid @RequestBody FinanceWithdrawConfirmReqVO reqVO) {
        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        financeAccountWithdrawService.withdrawConfirm(user, reqVO);
        return CommonResult.success();
    }

    /**
     * 个人企业清算单打印
     *
     * @param ids
     * @param response
     * @throws Exception
     */
    @GetMapping("/withdrawal/pdf")
    public void pdf(@RequestParam("ids") String ids, HttpServletResponse response) throws Exception {
        List<FinanceAccountWithdrawDO> financeAccountWithdrawDOS =
                financeAccountService.selectListAccountWithdrawByIds(Arrays.asList(ids.split(","))
                        .stream().map(Long::valueOf).collect(Collectors.toList()));
        Font header = PdfUtils.getFont();
        header.setSize(17);
        header.setStyle(Font.FontStyle.BOLD.getValue());
        Font bold = PdfUtils.getFont();
        bold.setStyle(Font.FontStyle.BOLD.getValue());

        PdfUtils.PdfDoc doc = PdfUtils.newPdfDoc();
        OutputStream os = response.getOutputStream();
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(String.format("余额提现_%s" +
                ".pdf", DateUtil.format(new Date(), "yyyyMMddHHmmss")), "UTF-8"));
        response.setContentType("application/pdf;charset=UTF-8");

        PdfWriter.getInstance(doc.getDoc(), os);
        doc.open();
        if (CollectionUtils.isEmpty(financeAccountWithdrawDOS)) {
            doc.addParagraph("未找到结算信息");
            doc.close();
            os.close();
            return;
        }
        //生成pdf
        financeAccountService.getPdf(financeAccountWithdrawDOS, doc, header, bold);


        doc.close();
        os.close();
    }


    @GetMapping("/checkBalance")
    @Operation(summary = "校验租户账户余额信息")
    @Parameter(name = "custId", description = "租客id", required = true, example = "1024")
    public CommonResult<Boolean> checkBalance(@RequestParam("custId") String custId) {
        FinanceAccountDO accountDO = financeAccountService.get(custId, FinanceCustomerTypeEnum.INDIVIDUAL.name());
        //存在账户的同时金额为负此时为true
        if (Objects.nonNull(accountDO) && BigDecimal.ZERO.compareTo(accountDO.getBalance()) > 0) {
            // 账户余额不小于0  返回false否则true
            return CommonResult.success(true);
        }
        return CommonResult.success(false);
    }



}
